package com.example.dictionary.service;

import com.example.memento.model.WordModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;

/**
 * funNLP 解析服务
 * 解析下载的 funNLP 资源库文件，并保存到数据库
 * 
 * funNLP 是一个几乎最全的中文NLP资源库，包含：
 * - 同义词库、反义词库、否定词库
 * - 中文分词词库
 * - 各种专业词典等
 */
@Service
public class FunNLPParser {
    
    private static final Logger log = LoggerFactory.getLogger(FunNLPParser.class);
    
    // 用于匹配分隔符（可能是空格、制表符、逗号等）
    private static final Pattern SYNOYM_SEPARATOR = Pattern.compile("[\\s,\\|]+");
    
    private final DownloadPathMappingService downloadPathMappingService;
    private final DictionaryDelegate dictionaryDelegate;
    
    // funNLP 的资源标识符
    private static final String FUNNLP_GIT_URL = "https://github.com/fighting41love/funNLP.git";
    private static final String FUNNLP_BRANCH = "master";
    
    // 近义词文件路径（相对于解压后的根目录）
    private static final String SYNONYM_FILE_1 = "data/同义词库、反义词库、否定词库/同义词库.txt";
    private static final String SYNONYM_FILE_2 = "data/中文分词词库整理/42537条伪原创词库.txt";
    
    public FunNLPParser(
            DownloadPathMappingService downloadPathMappingService,
            DictionaryDelegate dictionaryDelegate) {
        this.downloadPathMappingService = downloadPathMappingService;
        this.dictionaryDelegate = dictionaryDelegate;
    }
    
    /**
     * 解析 funNLP 的近义词数据
     * 
     * @throws IOException 如果文件不存在或读取失败
     */
    public void parseSynonyms() throws IOException {
        log.info("开始解析 funNLP 近义词数据...");
        
        // 1. 从下载映射服务获取文件地址
        String resourceKey = downloadPathMappingService.buildGitHubResourceKey(
                FUNNLP_GIT_URL, FUNNLP_BRANCH);
        Optional<String> downloadPathOpt = downloadPathMappingService.getDownloadPath(resourceKey);
        
        if (downloadPathOpt.isEmpty()) {
            throw new IllegalStateException(
                String.format("funNLP 下载路径未找到，资源标识符: %s。请先下载资源。", resourceKey)
            );
        }
        
        String downloadPath = downloadPathOpt.get();
        Path baseDir = Paths.get(downloadPath);
        
        // 检查是否存在 funNLP-master 子目录
        Path possibleFunNLPDir = baseDir.resolve("funNLP-master");
        if (Files.exists(possibleFunNLPDir) && Files.isDirectory(possibleFunNLPDir)) {
            baseDir = possibleFunNLPDir;
        }
        
        if (!Files.exists(baseDir)) {
            throw new IOException("funNLP 数据目录不存在: " + baseDir);
        }
        
        if (!Files.isDirectory(baseDir)) {
            throw new IOException("指定的路径不是目录: " + baseDir);
        }
        
        log.info("找到 funNLP 数据目录: {}", baseDir.toAbsolutePath());
        
        // 2. 解析近义词文件
        int totalSynonyms = 0;
        
        // 解析第一个近义词文件
        Path synonymFile1 = baseDir.resolve(SYNONYM_FILE_1);
        if (Files.exists(synonymFile1) && Files.isRegularFile(synonymFile1)) {
            log.info("解析近义词文件: {}", synonymFile1.getFileName());
            int count = parseSynonymFile(synonymFile1);
            totalSynonyms += count;
            log.info("✓ 完成解析 {} 个近义词关系", count);
        } else {
            log.warn("近义词文件不存在: {}", synonymFile1);
        }
        
        // 解析第二个近义词文件（伪原创词库）
        Path synonymFile2 = baseDir.resolve(SYNONYM_FILE_2);
        if (Files.exists(synonymFile2) && Files.isRegularFile(synonymFile2)) {
            log.info("解析伪原创词库文件: {}", synonymFile2.getFileName());
            int count = parseSynonymFile(synonymFile2);
            totalSynonyms += count;
            log.info("✓ 完成解析 {} 个近义词关系", count);
        } else {
            log.warn("伪原创词库文件不存在: {}", synonymFile2);
        }
        
        log.info("funNLP 近义词解析完成！总计处理 {} 个近义词关系", totalSynonyms);
    }
    
    /**
     * 解析单个近义词文件
     * 
     * @param file 文件路径
     * @return 处理的近义词关系数量
     */
    private int parseSynonymFile(Path file) throws IOException {
        int processedCount = 0;
        int lineNumber = 0;
        
        try (var lines = Files.lines(file)) {
            for (String line : lines.toList()) {
                lineNumber++;
                line = line.trim();
                
                // 跳过空行和注释行
                if (line.isEmpty() || line.startsWith("#") || line.startsWith("//")) {
                    continue;
                }
                
                // 解析行：可能是多种分隔符分隔的近义词组
                // 例如：词1 词2 词3 或 词1,词2,词3 或 词1|词2|词3
                String[] synonyms = SYNOYM_SEPARATOR.split(line);
                if (synonyms.length < 2) {
                    // 单个词，跳过（至少需要两个词才能构成近义词关系）
                    continue;
                }
                
                // 提取有效的近义词
                List<String> validSynonyms = new ArrayList<>();
                for (String synonym : synonyms) {
                    String trimmed = synonym.trim();
                    if (!trimmed.isEmpty() && trimmed.length() <= 200) {
                        validSynonyms.add(trimmed);
                    }
                }
                
                if (validSynonyms.size() < 2) {
                    continue;
                }
                
                // 处理近义词组：每个词都是其他词的近义词
                try {
                    processSynonymGroup(validSynonyms);
                    processedCount++;
                    
                    // 每处理 1000 个关系记录一次
                    if (processedCount % 1000 == 0) {
                        log.debug("已处理 {} 个近义词关系", processedCount);
                    }
                    
                } catch (Exception e) {
                    log.error("处理近义词失败 (行 {}): {}", lineNumber, line, e);
                    // 继续处理下一个，不中断整个解析过程
                }
            }
        }
        
        return processedCount;
    }
    
    /**
     * 处理一组近义词
     * 将组内所有词互相标记为近义词关系
     * 
     * @param synonyms 近义词列表
     */
    private void processSynonymGroup(List<String> synonyms) {
        // 对于每个词，将其他词作为近义词添加到 fullWordNames 中
        for (int i = 0; i < synonyms.size(); i++) {
            String word = synonyms.get(i);
            if (word == null || word.trim().isEmpty()) {
                continue;
            }
            
            // 查询或创建词汇对象
            Optional<WordModel> wordModelOpt = dictionaryDelegate.findWord(word);
            
            WordModel wordModel;
            if (wordModelOpt.isPresent()) {
                wordModel = wordModelOpt.get();
            } else {
                // 创建新的词汇对象
                wordModel = WordModel.builder()
                        .primaryWord(word)
                        .language("zh-CN")
                        .build();
            }
            
            // 将同组中的其他词添加为近义词（添加到 fullWordNames）
            for (int j = 0; j < synonyms.size(); j++) {
                if (i != j) {
                    String synonym = synonyms.get(j);
                    if (synonym != null && !synonym.trim().isEmpty()) {
                        // 添加为完整词名（近义词）
                        wordModel.addFullWordName(synonym);
                    }
                }
            }
            
            // 保存词汇对象
            dictionaryDelegate.saveWord(wordModel);
        }
    }
    
    /**
     * 解析指定的近义词文件
     * 
     * @param filePath 文件路径（相对路径，如 "data/同义词库、反义词库、否定词库/同义词库.txt"）
     * @throws IOException 如果文件不存在或读取失败
     */
    public void parseSynonymFile(String filePath) throws IOException {
        log.info("开始解析近义词文件: {}", filePath);
        
        // 获取数据目录
        String resourceKey = downloadPathMappingService.buildGitHubResourceKey(
                FUNNLP_GIT_URL, FUNNLP_BRANCH);
        Optional<String> downloadPathOpt = downloadPathMappingService.getDownloadPath(resourceKey);
        
        if (downloadPathOpt.isEmpty()) {
            throw new IllegalStateException("funNLP 下载路径未找到");
        }
        
        Path baseDir = Paths.get(downloadPathOpt.get());
        
        // 检查是否存在 funNLP-master 子目录
        Path possibleFunNLPDir = baseDir.resolve("funNLP-master");
        if (Files.exists(possibleFunNLPDir) && Files.isDirectory(possibleFunNLPDir)) {
            baseDir = possibleFunNLPDir;
        }
        
        Path synonymFile = baseDir.resolve(filePath);
        
        if (!Files.exists(synonymFile)) {
            throw new IOException("近义词文件不存在: " + synonymFile);
        }
        
        int processed = parseSynonymFile(synonymFile);
        log.info("完成解析近义词文件 {}，处理 {} 个近义词关系", filePath, processed);
    }
}

